#!/usr/bin/env python
#-*- coding:utf-8 -*-

from OpenGL.GLUT import *
from OpenGL.GLU import *
from OpenGL.GL import *

from math import *
from sys import *


# como a matriz gerada eh ortonormal, a inversa dela eh a transposta!
# simples.


def vetor_norma(vet):

	n = len(vet)
	
	a = 0
	for i in range(n):
		a += vet[i] * vet[i]
	
	return sqrt( a )


def vetor_prod_escalar(v1, v2):

	n, n2 = len(v1), len(v2)
	
	if n != n2:
		raise Exception( "Os vetores não possuem o mesmo tamanho!" )
	
	a = 0
	for i in range(n):
		a += v1[i] * v2[i]
	
	return a


def vetor_mul(vet, s):

	nvet = []
	for i in range( len(vet) ):
		nvet.append( vet[i] * s )
	
	return nvet


def vetor_add(v1, v2):

	n, n2 = len(v1), len(v2)
	
	if n != n2:
		raise Exception( "Os vetores não possuem o mesmo tamanho!" )

	nvet = []
	for i in range(n):
		nvet.append( v1[i] + v2[i] )
	
	return nvet	


def print_vetor(nome, vet):

	print( "Vetor " + nome + ":" )
	
	n = len(vet)
	
	for i in range(n):
		print( "   " + str( vet[i] ) )
		
	print( "   Norma: " + str( vetor_norma(vet) ) )
	print( "" )



def print_matriz(nome, mat):

	print( "Matriz " + nome + ":" )
	
	n = len(mat)
	
	for i in range(n):	
		for j in range(n):
			stdout.write( "   " + str(mat[i][j]) + " " )
		stdout.write("\n")
	
	print( "   Norma das linhas:" )
	for i in range(n):
		print( "   Linha " + str(i) + ": " + str( vetor_norma( mat[i] ) ) )
	
	print( "   Produto Escalar entre as linhas:" )
	for i in range(n):
		for j in range(n):
			if i != j:
				print( "   Linha " + str(i) + " com " + str(j) + ": " + \
					str( vetor_prod_escalar( mat[i], mat[j] ) ) \
				)				
	print( "" )
	


def matriz_x_vetor(mat, vet):

	n = len(vet)
	resp = [0.0] * n
	
	for i in range(n):
		for j in range(n):
			resp[i] += mat[i][j] * vet[j]

	return resp


def matriz_transposta(mat):

	n = len(mat)
	tmat = matriz_n_x_n( n )
	
	for i in range(n):
		for j in range(n):
			tmat[i][j] = mat[j][i]
	
	return tmat


def matriz_n_x_n(n):
	
	mat = []
	for i in range(n):
		mat.append( [0] * n )
	
	return mat


def dct(x):

	n = len(x)	
	mat = matriz_n_x_n( n )
	
	for i in range(n):
		mat[0][i] = 1.0 / sqrt(n)

	for i in range(1, n): # de 1 ate n
		for j in range(n):
			mat[i][j] = \
				sqrt( 2.0 / n) * \
				cos( i * pi/(2*n) * (2*j + 1) )

	print_matriz( "DCT", mat )
	return matriz_x_vetor( mat, x )


def idct(x):

	n = len(x)
	mat = matriz_n_x_n( n )
	
	for i in range(n):
		mat[0][i] = 1.0 / sqrt( n ) # no original, havia isso, que eh igual: sqrt( 1.0 / n )
	
	for i in range(1, n):
		for j in range(n):
			mat[i][j] = \
				sqrt( 2.0 / n ) * \
				cos( i * pi/(2*n) * (2*j + 1) )
	
	print_matriz( "IDCT", mat )

	tmat = matriz_transposta( mat )
	print_matriz( "IDCT transposta", tmat )

	return matriz_x_vetor( tmat, x )




def seta(vet):
	glPushMatrix()

	zoom = 0.25
	glScalef( zoom, zoom, zoom )
	
	glLineWidth( 5 )
	glBegin( GL_LINES )
	
	glColor3f( 0.1, 0.1, 0.1 )	
	glVertex3f( 0, 0, 0 )
		
	glColor3f( 0.8, 1.0, 1.0 )
	glVertex3f( vet[0], vet[1], vet[2] )
	
	glEnd()
	
	glPointSize( 8.0 )
	glBegin( GL_POINTS )
	
	glColor3f( cor[0], cor[1], cor[2] )
	glVertex3f( vet[0], vet[1], vet[2] )
	
	glEnd()

	glPopMatrix()
	

def display():
	glMatrixMode(GL_PROJECTION)
	glLoadIdentity()
	glMatrixMode(GL_MODELVIEW)
	glLoadIdentity()

	glClearColor( 0.2, 0.2, 0.2, 0.2 )
	glClear( GL_COLOR_BUFFER_BIT )

	global atual
	seta( atual )

	glutSwapBuffers()
	return

def idle():

	global atual, atual_f, entrada, saida

	atual_f += atual_f_inc
	atual = vetor_add( \
		vetor_mul( entrada, (1 - atual_f) ), \
		vetor_mul( saida, atual_f ) \
	)
	
	if atual_f > 1.0:
		atual_f = 0.0

		entrada, saida = saida, entrada
				
		global indo, cor
		if indo:
			cor = [1, 1, 0]
		else:
			cor = [1, 0, 0]
		
		indo = not indo
		
	glutPostRedisplay()


glutInit( [] )
glutInitDisplayMode( GLUT_DOUBLE | GLUT_RGB )
glutInitWindowSize( 500, 400 )
glutCreateWindow( "Demonstracao da DCT de forma visual" )

glutIdleFunc(idle)
glutDisplayFunc(display)

entrada = [1, 2, 3]
saida = None
atual = None
atual_f = 0.0
atual_f_inc = 0.001
cor = [1, 0, 0]
indo = True

saida = dct( entrada )
atual = entrada
atual_f = 0

print_vetor( "Entrada", entrada )
print_vetor( "Saida", saida )

glutMainLoop()

